#include "stdafx.h"
#include "FBMTerrain.h"
#include <cmath>

//-------------------------------------------------------------------------
// constructors
//-------------------------------------------------------------------------

CfBm::CfBm()
{
	m_bPrecomputefBmSpectralWeights = false;
	m_pfExponentArrayfBm = NULL;
};

//-------------------------------------------------------------------------
// destructors
//-------------------------------------------------------------------------

CfBm::~CfBm()
{
	m_bPrecomputefBmSpectralWeights = false;
	if (m_pfExponentArrayfBm != NULL) 
	{
		delete m_pfExponentArrayfBm;
		m_pfExponentArrayfBm = NULL;
	}
};

//-------------------------------------------------------------------------
// member functions
//-------------------------------------------------------------------------

float CfBm::fBm(vector3f vec3f, float H, float lacunarity, float octaves)
{

	int		i;
	float	fBm_value, frequency, remainder;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }

	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// Spectral construction loop

	for (i=0; i<octaves; i++)
	{
	    fBm_value += m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
	    vec3f *= lacunarity;
	}
	
	remainder = octaves - (int)octaves;

	if (remainder != 0.0f)
	{
	    fBm_value += remainder * m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
	}

	return fBm_value;
}

//-------------------------------------------------------------------------

float CfBm::fBmTurbulence(vector3f vec3f, float H, float lacunarity, float octaves)
{

	int		i;
	float	fBm_value, frequency, remainder;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }

	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// Spectral construction loop

	for (i=0; i<octaves; i++)
	{
		float abs_noise = m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
		if (abs_noise < 0.0f) abs_noise = -abs_noise;
	    fBm_value += abs_noise;
	    vec3f *= lacunarity;
	}
	
	remainder = octaves - (int)octaves;

	if (remainder != 0.0f)
	{
	    fBm_value += remainder * m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
	}

	return fBm_value;
}

//-------------------------------------------------------------------------

float CfBm::MultiFractal(vector3f vec3f, float H, float lacunarity, float octaves, float offset)
{

	int		i;
	float	fBm_value, frequency, remainder;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }

	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// Spectral construction loop

	for (i=0; i<octaves; i++)
	{
	    fBm_value += offset * frequency * m_PNoise.PNoise3D(vec3f);
	    vec3f *= lacunarity;
	}
	
	remainder = octaves - (int)octaves;

	if (remainder != 0.0f)
	{
	    fBm_value += remainder * m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
	}

	return fBm_value;
}

//-------------------------------------------------------------------------

float CfBm::HeteroMultiFractal(vector3f vec3f, float H, float lacunarity, float octaves, float offset)
{

	int		i;
	float	fBm_value, frequency, remainder, increment;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }

	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// First unscaled octave

	fBm_value = offset + m_PNoise.PNoise3D(vec3f);
	vec3f *= lacunarity;

	// Spectral construction loop

	for (i=1; i<octaves; i++)
	{
		increment = m_PNoise.PNoise3D(vec3f) + offset;
		increment *= m_pfExponentArrayfBm[i];
		increment *= fBm_value;
		fBm_value += increment;
		vec3f *= lacunarity;
	}
	
	remainder = octaves - (int)octaves;

	if (remainder != 0.0f)
	{
		increment = (m_PNoise.PNoise3D(vec3f) + offset) * m_pfExponentArrayfBm[i];
	    fBm_value += remainder * increment * fBm_value;
	}

	return fBm_value;
}

//-------------------------------------------------------------------------

float CfBm::HybridMultiFractal(vector3f vec3f, float H, float lacunarity, float octaves, float offset)
{

	int		i;
	float	fBm_value, frequency, remainder, result, weight, signal;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }

	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// First unscaled octave

	result = (offset + m_PNoise.PNoise3D(vec3f)) * m_pfExponentArrayfBm[0];
	weight = result;
	vec3f *= lacunarity;

	// Spectral construction loop

	for (i=1; i<octaves; i++)
	{
	    if (weight > 1.0f)	weight = 1.0f;
	    signal = (m_PNoise.PNoise3D(vec3f) + offset) * m_pfExponentArrayfBm[i];
	    result += weight * signal;
	    weight *= signal;
		vec3f *= lacunarity;
	}
	
	remainder = octaves - (int)octaves;

	if (remainder != 0.0f)
	{
	    result += remainder * m_PNoise.PNoise3D(vec3f) * m_pfExponentArrayfBm[i];
	}

	fBm_value = (result * 0.5f) - 1.0f;
	return fBm_value;
}

//-------------------------------------------------------------------------

float CfBm::RidgedMultiFractal(vector3f vec3f, float H, float lacunarity, float octaves, float offset, float gain)
{

	int		i;
	float	fBm_value, frequency, result, weight, signal;
	
	// Precompute and store spectral weights

	if (!m_bPrecomputefBmSpectralWeights)
	{
	    // Seize required memory for exponent array

	    m_pfExponentArrayfBm = new float[(int)octaves+1];
	    frequency			= 1.0f;

	    for (i=0; i<=octaves; i++)
	    {
		  m_pfExponentArrayfBm[i] = powf(frequency, -H); // compute weight for each frequency
		  frequency *= lacunarity;
	    }
	    m_bPrecomputefBmSpectralWeights = true;
	}

	// Zero fBm value

	fBm_value = 0.0f;
	
	// First unscaled octave

	signal = m_PNoise.PNoise3D(vec3f);
	if (signal < 0.0f) signal = -signal;		// abs(signal) creates ridges
	signal = offset - signal;					// invert and translate
	signal *= signal;							// signal^2 sharpens ridges
	result = signal;
	weight = 1.0f;

	// Spectral construction loop

	for (i=1; i<octaves; i++)
	{
		vec3f *= lacunarity;
	    weight = signal * gain;					// weight successive contributions by previous signal
	    if (weight > 1.0f) weight = 1.0f;
	    if (weight < 0.0f) weight = 0.0f;
	    signal = m_PNoise.PNoise3D(vec3f);
	    if (signal < 0.0f) signal = -signal;
	    signal = offset - signal;
	    signal *= signal;
	    signal *= weight;
	    result += signal * m_pfExponentArrayfBm[i];
	}
	
	fBm_value = (result - 1.0f) * 0.5f;
	return fBm_value;
}